package com.tengju.bff.interfaces.covercharge.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tengju.bff.interfaces.covercharge.constant.CooperationEnum;
import com.tengju.bff.interfaces.covercharge.constant.CoverChargeEnum;
import com.tengju.bff.interfaces.covercharge.constant.InvoiceEnum;
import com.tengju.bff.interfaces.covercharge.constant.LetaxWithdrawStatusEnum;
import com.tengju.bff.interfaces.covercharge.constant.SelfCertificationTypeEnum;
import com.tengju.bff.interfaces.covercharge.constant.SelfWithdrawStatusEnum;
import com.tengju.bff.interfaces.covercharge.constant.WithdrawalCancelEnum;
import com.tengju.bff.interfaces.covercharge.entity.dto.RegisteredInfo;
import com.tengju.bff.interfaces.covercharge.entity.dto.WithdrawalReason;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceInvoiceShippingLog;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceLetaxWithdrawLog;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceSelfCertification;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceSelfCertificationWithdraw;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceWithdarwCycleAdd;
import com.tengju.bff.interfaces.covercharge.entity.vo.RecordDetail;
import com.tengju.bff.interfaces.covercharge.entity.vo.WithdrawApplyVo;
import com.tengju.bff.interfaces.covercharge.entity.vo.WithdrawRecordVo;
import com.tengju.bff.interfaces.covercharge.mapper.ServiceSelfCertificationMapper;
import com.tengju.bff.interfaces.covercharge.service.IAttachmentService;
import com.tengju.bff.interfaces.covercharge.service.IServiceInvoiceShippingLogService;
import com.tengju.bff.interfaces.covercharge.service.IServiceLetaxWithdrawLogService;
import com.tengju.bff.interfaces.covercharge.service.IServiceSelfCertificationWithdrawService;
import com.tengju.bff.interfaces.covercharge.service.IServiceWithdarwCycleAddService;
import com.tengju.bff.interfaces.covercharge.service.IWithdrawRecodService;
import com.tengju.bff.interfaces.covercharge.util.DateTimeUtils;
import com.tengju.settlement.domain.model.account.UserIdCode;
import com.tengju.settlement.domain.model.depository.*;
import com.tengju.user.application.shared.ApplicationException;
import com.tengju.user.application.shared.ApplicationExceptionCode;
import com.zoi7.component.core.exception.ServiceException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 提现申请记录相关
 *
 * @author fwy
 * @since 2020-02-24
 */
@Service
@Slf4j
public class WithdrawRecordServiceImpl implements IWithdrawRecodService {

    @Autowired
    private IServiceLetaxWithdrawLogService serviceLetaxWithdrawLogService;

    @Autowired
    private IServiceSelfCertificationWithdrawService serviceSelfCertificationWithdrawService;

    @Autowired
    private IServiceWithdarwCycleAddService serviceWithdarwCycleAddService;

    @Autowired
    private IAttachmentService attachmentService;

    @Autowired
    private ServiceSelfCertificationMapper serviceSelfCertificationMapper;

    @Autowired
    private IServiceInvoiceShippingLogService serviceInvoiceShippingLogService;
    @Autowired
    private DepositoryAccountRepository depositoryAccountRepository;
    @Autowired
    private DepositoryBankCardRepository depositoryBankCardRepository;


    @Value("${depository.account.whiteList}")
    private String DepAccountWhiteList;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WithdrawApplyVo getWithdrawList(Integer idCode, String platForm) {
        if (StringUtils.isEmpty(platForm)) {
            throw new ServiceException("传入平台编码不能为空");
        }

        //默认三个月前的时间
        Date dateTime = DateUtils.addMonths(new Date(), -3);
        String time = DateUtil.format(dateTime, "yyyy-MM-dd");
        //DT
        if(CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getPlatform().equals(platForm)){
            //默认上一个提现周期的开始时间
            /*Date nowDate = new Date();
            String cycleDay = ConfigUtil.getConfig().getString("withdraw.cycle.day", "10");
            String startDateStr = DateUtil.format(nowDate, DateTimeUtils.MONTH_FORMAT) + "-" + (Integer.parseInt(cycleDay) + 1) + " 00:00:00";
            Date startDate = DateUtil.parse(startDateStr, DateTimeUtils.DEFAULT_DATE_TIME_FORMAT);
            if (nowDate.before(startDate)) {
                startDate = DateTimeUtils.addMonths(startDate, -2);
            }else{
                startDate = DateTimeUtils.addMonths(startDate, -1);
            }
            time = DateUtil.format(startDate, DateTimeUtils.DEFAULT_DATE_TIME_FORMAT);*/
            time="2020-10-13 00:00:00";
            log.info("[获取提现记录时间]"+time);
        }

        WithdrawApplyVo applyVo = new WithdrawApplyVo();
        BigDecimal isSuedAmount = new BigDecimal(BigInteger.ZERO);
        BigDecimal beIsSuedAmount = new BigDecimal(BigInteger.ZERO);

        //查询个人提现审批
        List<WithdrawRecordVo> perResults = serviceLetaxWithdrawLogService.getWithdrawList(idCode, platForm, CooperationEnum.PERSONAL.getCode(), time);
        BigDecimal perIsSuedAmount = serviceLetaxWithdrawLogService.getIssuedAmount(idCode, platForm, CooperationEnum.PERSONAL.getCode(), time);
        BigDecimal perbeIsSuedAmount = serviceLetaxWithdrawLogService.getBeIssuedAmount(idCode, platForm, CooperationEnum.PERSONAL.getCode(), time);
        List<WithdrawRecordVo> results = new ArrayList<>(perResults);
        isSuedAmount = isSuedAmount.add(perIsSuedAmount);
        beIsSuedAmount = beIsSuedAmount.add(perbeIsSuedAmount);
        //查询注册个体户提现审批
        List<WithdrawRecordVo> regesults = serviceLetaxWithdrawLogService.getWithdrawList(idCode, platForm, CooperationEnum.REGISTSOHO.getCode(), time);
        BigDecimal regIsSuedAmount = serviceLetaxWithdrawLogService.getIssuedAmount(idCode, platForm, CooperationEnum.REGISTSOHO.getCode(), time);
        BigDecimal regBeIsSuedAmount = serviceLetaxWithdrawLogService.getBeIssuedAmount(idCode, platForm, CooperationEnum.REGISTSOHO.getCode(), time);
        results.addAll(regesults);
        isSuedAmount = isSuedAmount.add(regIsSuedAmount);
        beIsSuedAmount = beIsSuedAmount.add(regBeIsSuedAmount);
        //查询自认证个体户提现审批
        List<WithdrawRecordVo> dualResults = serviceSelfCertificationWithdrawService.getWithdrawList(idCode, platForm, SelfCertificationTypeEnum.SINGLE.getCode(), time);
        BigDecimal dualIsSuedAmount = serviceSelfCertificationWithdrawService.getIssuedAmount(idCode, platForm, SelfCertificationTypeEnum.SINGLE.getCode(), time);
        BigDecimal dualBeIsSuedAmount = serviceSelfCertificationWithdrawService.getBeIssuedAmount(idCode, platForm, SelfCertificationTypeEnum.SINGLE.getCode(), time);
        results.addAll(dualResults);
        isSuedAmount = isSuedAmount.add(dualIsSuedAmount);
        beIsSuedAmount = beIsSuedAmount.add(dualBeIsSuedAmount);
        //查询自认证企业提现审批
        List<WithdrawRecordVo> comResults = serviceSelfCertificationWithdrawService.getWithdrawList(idCode, platForm, SelfCertificationTypeEnum.COMPANY.getCode(), time);
        BigDecimal comIsSuedAmount = serviceSelfCertificationWithdrawService.getIssuedAmount(idCode, platForm, SelfCertificationTypeEnum.COMPANY.getCode(), time);
        BigDecimal comBeIsSuedAmount = serviceSelfCertificationWithdrawService.getBeIssuedAmount(idCode, platForm, SelfCertificationTypeEnum.COMPANY.getCode(), time);
        results.addAll(comResults);
        isSuedAmount = isSuedAmount.add(comIsSuedAmount);
        beIsSuedAmount = beIsSuedAmount.add(comBeIsSuedAmount);

        //根据时间排序
        this.sort(results);

        applyVo.setWithdrawRecords(results);
        applyVo.setBeIssuedAmount(beIsSuedAmount);
        applyVo.setIssuedAmount(isSuedAmount);
        return applyVo;
    }

    @Override
    public RecordDetail getRecordDetail(String identity, Integer recordId) {
        RecordDetail recordDetail = new RecordDetail();
        if (CooperationEnum.PERSONAL.getCode().equals(identity)) {
            //个人
            ServiceLetaxWithdrawLog withdrawLog = serviceLetaxWithdrawLogService.getById(recordId);
            if (withdrawLog == null) {
                throw new ServiceException("未找到该申请记录");
            }
            recordDetail = letaxToRecordDetail(withdrawLog);
        } else if (CooperationEnum.REGISTSOHO.getCode().equals(identity)) {
            //注册个体户
            ServiceLetaxWithdrawLog withdrawLog = serviceLetaxWithdrawLogService.getById(recordId);
            if (withdrawLog == null) {
                throw new ServiceException("未找到该申请记录");
            }
            recordDetail = letaxToRecordDetail(withdrawLog);
        } else if (CooperationEnum.CERTIFIEDINDIVIDUAL.getCode().equals(identity)) {
            //自认证个体户
            ServiceSelfCertificationWithdraw withdraw = serviceSelfCertificationWithdrawService.getById(recordId);
            if (withdraw == null) {
                throw new ServiceException("未找到该申请记录");
            }
            recordDetail = selfToRecordDetail(withdraw, identity);
        } else if (CooperationEnum.CERTIFIEDBUSINESS.getCode().equals(identity)) {
            //自认证企业
            ServiceSelfCertificationWithdraw withdraw = serviceSelfCertificationWithdrawService.getById(recordId);
            if (withdraw == null) {
                throw new ServiceException("未找到该申请记录");
            }
            recordDetail = selfToRecordDetail(withdraw, identity);
        } else {
            throw new ServiceException("身份有误");
        }
        return recordDetail;
    }

    /**
     * 个人，注册个体户数据转换
     *
     * @param withdrawLog
     * @return
     */
    private RecordDetail letaxToRecordDetail(ServiceLetaxWithdrawLog withdrawLog) {
        RecordDetail recordDetail = new RecordDetail();
        recordDetail.setId(withdrawLog.getId());
        recordDetail.setMoney(withdrawLog.getMoney());
        recordDetail.setCreatedAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getCreatedAt()));
        CooperationEnum cooperationEnum = CooperationEnum.getCooperationDesc(withdrawLog.getAuthType());
        recordDetail.setIdentityName(Objects.isNull(cooperationEnum) ? null : cooperationEnum.getDesc());
        ServiceWithdarwCycleAdd add = serviceWithdarwCycleAddService.getById(withdrawLog.getCycleAddId());
        recordDetail.setRealAmount(withdrawLog.getMoney().multiply((BigDecimal.ONE.subtract(add.getRatio()))));
        recordDetail.setPaymentime(DateTimeUtils.parseDateAsString(add.getWithdrawTime(),DateTimeUtils.DEFAULT_DATE_TIME_FORMAT));
        recordDetail.setRate(add.getRatio().multiply(new BigDecimal(100)).toPlainString());
        recordDetail.setPaymentRemark(add.getRemark());
        recordDetail.setStatus(withdrawLog.getStatus());
        LetaxWithdrawStatusEnum statusEnum = LetaxWithdrawStatusEnum.getStatusDesc(withdrawLog.getStatus());
        recordDetail.setStatusName(Objects.isNull(statusEnum) ? null : statusEnum.getDesc());
        if (CooperationEnum.PERSONAL.getCode().equals(withdrawLog.getAuthType())) {
            JSONObject result = JSONObject.parseObject(withdrawLog.getRegisteredInfo());
            recordDetail.setName(result.getString("idcard_name"));
            recordDetail.setBankName(result.getString("bank_name"));
            recordDetail.setIdCardNo(result.getString("idcard_no"));
            recordDetail.setBankNo(result.getString("bank_no"));
        } else {
            List<RegisteredInfo> infos = JSON.parseArray(withdrawLog.getRegisteredInfo(), RegisteredInfo.class);
            for (RegisteredInfo info : infos) {
                recordDetail.setName(info.getName());
                recordDetail.setBankName(info.getBankName());
                recordDetail.setBankNo(info.getBankNo());
                recordDetail.setIdCardNo(info.getIdcardNo());
                //注册工商户多余信息
                recordDetail.setMerchantName(info.getMerchantName());
                recordDetail.setMerchantTaxNumber(info.getMerchantTaxNumber());
            }
        }
        List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawLog.getReason(), WithdrawalReason.class);
        recordDetail.setReason(withdrawalReasonList);
        recordDetail.setRemark(withdrawLog.getApplyRemark());
        recordDetail.setRejectReason(withdrawLog.getRemark());
        recordDetail.setUpdatedAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getUpdatedAt()));
        recordDetail.setCheckAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getCheckAt()));
        if (withdrawLog.getCancelRemark().equals(WithdrawalCancelEnum.self.getDesc())) {
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String dateStr = withdrawLog.getUpdatedAt().format(fmt);
            recordDetail.setCancelRemark(dateStr + " 您主动取消了该笔申请");
        } else {
            recordDetail.setCancelRemark(withdrawLog.getCancelRemark());
        }

        return recordDetail;
    }

    /**
     * 自认证企业或者个体户数据转换
     *
     * @param withdrawLog
     * @param identity
     * @return
     */
    private RecordDetail selfToRecordDetail(ServiceSelfCertificationWithdraw withdrawLog, String identity) {
        RecordDetail recordDetail = new RecordDetail();
        recordDetail.setId(withdrawLog.getId());
        recordDetail.setMoney(withdrawLog.getMoney());
        recordDetail.setCreatedAt(withdrawLog.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        CooperationEnum cooperationEnum = CooperationEnum.getCooperationDesc(identity);
        recordDetail.setIdentityName(Objects.isNull(cooperationEnum) ? null : cooperationEnum.getDesc());
        InvoiceEnum invoiceEnum = InvoiceEnum.getInvoiceDesc(withdrawLog.getInvoice());
        recordDetail.setInvoiceType(Objects.isNull(invoiceEnum) ? null : invoiceEnum.getDesc());
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotBlank(withdrawLog.getInvoiceImg())) {
            String[] str = withdrawLog.getInvoiceImg().split(",");
            for (int i = 0; i < str.length; i++) {
                String url = attachmentService.getUrl(str[i]);
                if (i == 0) {
                    sb.append(url);
                } else {
                    sb.append(",").append(url);
                }
            }
        }
        recordDetail.setInvoiceUrl(sb.toString());
        recordDetail.setInvoiceId(withdrawLog.getInvoiceImg());
        recordDetail.setStatus(withdrawLog.getStatus());
        SelfWithdrawStatusEnum statusEnum = null;
        if(withdrawLog.getStatus().equals(SelfWithdrawStatusEnum.IN_DISTRIBUT.getCode())) {
            statusEnum = SelfWithdrawStatusEnum.SPASS;
        } else {
            statusEnum = SelfWithdrawStatusEnum.getStatusDesc(withdrawLog.getStatus());
        }
        recordDetail.setStatusName(Objects.isNull(statusEnum) ? null : statusEnum.getDesc());
        ServiceSelfCertification certification = serviceSelfCertificationMapper.selectById(withdrawLog.getSelfCertificationId());

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(new UserIdCode(certification.getIdCode()));
        }
        DepositoryAccount depositoryAccount;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(certification.getIdCode()), DepositoryChannel.INTERNAL);
        } else {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(certification.getIdCode()), DepositoryChannel.PING_AN);
        }
        List<DepositoryAccountId> depositoryAccountIds = List.of(depositoryAccount.getDepositoryAccountId());
        List<DepositoryBankCard> bankCards = depositoryBankCardRepository
                .getByDepositoryAccountIdsStatus(depositoryAccountIds, List.of(BindStatus.SUCCESS));
        if (CollectionUtils.isEmpty(bankCards)) {
            throw ApplicationException.error(ApplicationExceptionCode.INVALID_DATA,"未绑卡");
        }
        recordDetail.setName(certification.getCompanyName());
        recordDetail.setBankNo(withdrawLog.getBankNo());
        recordDetail.setBankName(bankCards.get(0).getBankName());
        List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawLog.getReasonNew(), WithdrawalReason.class);
        recordDetail.setReason(withdrawalReasonList);
        recordDetail.setRemark(withdrawLog.getApplyRemark());
        recordDetail.setRejectReason(withdrawLog.getRemark());
        recordDetail.setUpdatedAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getUpdatedAt()));
        recordDetail.setCheckAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getCheckAt()));
        recordDetail.setRecheckAt(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getRecheckt()));
        recordDetail.setPaymentime(DateTimeUtils.parseLocalDateTimeToString(withdrawLog.getPaymentTime()));
        if (SelfWithdrawStatusEnum.CANCEL.getCode().equals(withdrawLog.getStatus())) {
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String dateStr = withdrawLog.getUpdatedAt().format(fmt);
            recordDetail.setCancelRemark(dateStr + " 您主动取消了该笔申请");
        }
        //查询
        //获取邮寄发票信息
        QueryWrapper<ServiceInvoiceShippingLog> invoiceQueryWrapper = new QueryWrapper<>();
        invoiceQueryWrapper.eq("self_withdraw_id", withdrawLog.getId());
        invoiceQueryWrapper.eq("type", 1);
        ServiceInvoiceShippingLog shippingLog = serviceInvoiceShippingLogService.getOne(invoiceQueryWrapper);
        if (shippingLog != null) {
            recordDetail.setShippingNo(shippingLog.getShippingNo());
            recordDetail.setExpressName(shippingLog.getExpressName());
            //查询图片
            String url = attachmentService.getUrl(String.valueOf(shippingLog.getImgId()));
            log.info("提现详情查看图片:{}", url);
            recordDetail.setImgId(url);
        }
        //获取公司邮寄信息
        QueryWrapper<ServiceInvoiceShippingLog> invoiceQueryWrapper2 = new QueryWrapper<>();
        invoiceQueryWrapper2.eq("self_withdraw_id", withdrawLog.getId());
        invoiceQueryWrapper2.eq("type", 2);
        ServiceInvoiceShippingLog logs = serviceInvoiceShippingLogService.getOne(invoiceQueryWrapper2);
        if (logs != null) {
            recordDetail.setBackExpressName(logs.getExpressName());
            recordDetail.setBackShippingNo(logs.getShippingNo());
        }
        return recordDetail;

    }

    //排序（创建时间倒叙）
    private void sort(List<WithdrawRecordVo> results) {
        results.sort((o1, o2) -> {
            if (o1.getCreatedAt().compareTo(o2.getCreatedAt()) < 0) {
                return 1;
            }
            if (o1.getCreatedAt() == o2.getCreatedAt()) {
                return 0;
            }
            return -1;
        });
    }

    /**
     * app端获取用户DT端从2020-10-13 00:00:00开始是否有修改提现申请理由
     * @param idCode 代理id
     * @return
     */
    @Override
    public Boolean getUpdateReasonStatus(Integer idCode){
        //注册个体户/个人
        QueryWrapper<ServiceLetaxWithdrawLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id_code", idCode);
        queryWrapper.eq("platform_code", CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getPlatform());
        queryWrapper.ge("created_at", "2020-10-13 00:00:00");
        queryWrapper.isNull("reason");
        Integer leTaxNum = serviceLetaxWithdrawLogService.count(queryWrapper);

        //自认证企业
        QueryWrapper<ServiceSelfCertificationWithdraw> selfQueryWrapper = new QueryWrapper<>();
        selfQueryWrapper.eq("id_code", idCode);
        selfQueryWrapper.eq("platform_code", CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getPlatform());
        selfQueryWrapper.ge("created_at", "2020-10-13 00:00:00");
        selfQueryWrapper.isNull("reason_new");
        Integer selfNum=serviceSelfCertificationWithdrawService.count(selfQueryWrapper);

        //如果有申请理由为空的则去判断
        if(leTaxNum.compareTo(0)>0 || selfNum.compareTo(0)>0){
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
}
